From 8f19099f1ae87591802a4b0aafb12ab49bd011da Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Wed, 4 May 2022 14:56:48 +0200 Subject: [PATCH] GdkWin32: Add support for DirectManipulation Adds support for Precision TouchPads (PTPs) gestures and scroll events. --- gdk/win32/gdkevents-win32.c | 10 + gdk/win32/gdkinput-dmanipulation.c | 586 +++++++++++++++++++++++++++++ gdk/win32/gdkinput-dmanipulation.h | 32 ++ gdk/win32/gdkmain-win32.c | 83 ++++ gdk/win32/gdkprivate-win32.h | 10 + gdk/win32/gdksurface-win32.c | 11 +- gdk/win32/gdksurface-win32.h | 4 + gdk/win32/meson.build | 1 + 8 files changed, 735 insertions(+), 2 deletions(-) create mode 100644 gdk/win32/gdkinput-dmanipulation.c create mode 100644 gdk/win32/gdkinput-dmanipulation.h diff --git a/gdk/win32/gdkevents-win32.c b/gdk/win32/gdkevents-win32.c index c928a14142..23f99c1ab7 100644 --- a/gdk/win32/gdkevents-win32.c +++ b/gdk/win32/gdkevents-win32.c @@ -58,6 +58,7 @@ #include "gdkdeviceprivate.h" #include "gdkdevice-virtual.h" #include "gdkdevice-wintab.h" +#include "gdkinput-dmanipulation.h" #include "gdkinput-winpointer.h" #include "gdkwin32dnd.h" #include "gdkwin32dnd-private.h" @@ -2656,6 +2657,13 @@ gdk_event_translate (MSG *msg, return_val = TRUE; break; + case DM_POINTERHITTEST: + gdk_dmanipulation_maybe_add_contact (window, msg); + + *ret_valp = 0; + return_val = TRUE; + break; + case WM_MOUSEWHEEL: case WM_MOUSEHWHEEL: { @@ -3156,6 +3164,8 @@ gdk_event_translate (MSG *msg, if (win32_display->tablet_input_api == GDK_WIN32_TABLET_INPUT_API_WINPOINTER) gdk_winpointer_finalize_surface (window); + gdk_dmanipulation_finalize_surface (window); + return_val = FALSE; break; diff --git a/gdk/win32/gdkinput-dmanipulation.c b/gdk/win32/gdkinput-dmanipulation.c new file mode 100644 index 0000000000..49244f02c2 --- /dev/null +++ b/gdk/win32/gdkinput-dmanipulation.c @@ -0,0 +1,586 @@ +/* gdkinput-dmanipulation.c + * + * Copyright © 2022 the GTK team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +/* {{{ */ + +#ifdef WINVER +#undef WINVER +#endif +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +#define WINVER 0x0603 +#define _WIN32_WINNT 0x0603 +#define COBJMACROS +#include "config.h" + +#include +#include "gdkwin32.h" +#include "gdkprivate-win32.h" +#include "gdkdevicemanager-win32.h" +#include "gdkdevice-virtual.h" +#include "gdkdeviceprivate.h" +#include "gdkdisplayprivate.h" +#include "gdkeventsprivate.h" +#include "gdkseatdefaultprivate.h" +#include "gdkinput-dmanipulation.h" +#include "winpointer.h" + +#include +#include + +typedef BOOL +(WINAPI *getPointerType_t)(UINT32 pointerId, POINTER_INPUT_TYPE *pointerType); +static getPointerType_t getPointerType; + +static IDirectManipulationManager *dmanipulation_manager; + +typedef struct +{ + IDirectManipulationViewportEventHandlerVtbl *vtable; + LONG reference_count; + + enum { + GESTURE_PAN, + GESTURE_ZOOM, + } gesture; + + GdkTouchpadGesturePhase phase; + gpointer sequence; + + float scale; + float pan_x; + float pan_y; + + GdkSurface *surface; + GdkDevice *device; +} +DManipEventHandler; + +static void dmanip_event_handler_running_state_clear (DManipEventHandler *handler); +static void dmanip_event_handler_free (DManipEventHandler *handler); + +static void reset_viewport (IDirectManipulationViewport *viewport); + +static gpointer util_get_next_sequence (void); +static GdkModifierType util_get_modifier_state (void); +static gboolean util_handler_free (gpointer); + +/* }}} */ +/* {{{ ViewportEventHandler */ + +static STDMETHODIMP_ (ULONG) +DManipEventHandler_AddRef (IDirectManipulationViewportEventHandler *self_) +{ + DManipEventHandler *self = (DManipEventHandler*) self_; + + return (ULONG) InterlockedIncrement (&self->reference_count); +} + +static STDMETHODIMP_ (ULONG) +DManipEventHandler_Release (IDirectManipulationViewportEventHandler *self_) +{ + DManipEventHandler *self = (DManipEventHandler*) self_; + + /* NOTE: This may run from a worker thread */ + + LONG new_reference_count = InterlockedDecrement (&self->reference_count); + + if (new_reference_count <= 0) + { + /* For safety, schedule the cleanup to be executed + * on the main thread */ + g_idle_add (util_handler_free, self); + + return 0; + } + + return (ULONG) new_reference_count; +} + +static STDMETHODIMP +DManipEventHandler_QueryInterface (IDirectManipulationViewportEventHandler *self_, + REFIID riid, + void **ppvObject) +{ + DManipEventHandler *self = (DManipEventHandler*) self_; + + if G_UNLIKELY (!self || !ppvObject) + return E_POINTER; + + *ppvObject = NULL; + + if (IsEqualGUID (riid, &IID_IUnknown)) + *ppvObject = self; + else if (IsEqualGUID (riid, &IID_IDirectManipulationViewportEventHandler)) + *ppvObject = self; + + if (*ppvObject == NULL) + return E_NOINTERFACE; + + DManipEventHandler_AddRef (self_); + return S_OK; +} + +/* NOTE: + * + * All DManipEventHandler callbacks are fired from the main thread */ + +static STDMETHODIMP +DManipEventHandler_OnViewportUpdated (IDirectManipulationViewportEventHandler *self_, + IDirectManipulationViewport *viewport) +{ + return S_OK; +} + +static STDMETHODIMP +DManipEventHandler_OnContentUpdated (IDirectManipulationViewportEventHandler *self_, + IDirectManipulationViewport *viewport, + IDirectManipulationContent *content) +{ + DManipEventHandler *self = (DManipEventHandler*) self_; + float transform[6] = {1., 0., 0., 1., 0., 0.}; + HRESULT hr; + + hr = IDirectManipulationContent_GetContentTransform (content, transform, + G_N_ELEMENTS (transform)); + HR_CHECK_RETURN_VAL (hr, E_FAIL); + + switch (self->gesture) + { + case GESTURE_PAN: + { + GdkModifierType state; + uint32_t time; + float pan_x; + float pan_y; + GdkEvent *event; + + pan_x = transform[4]; + pan_y = transform[5]; + + state = util_get_modifier_state (); + time = (uint32_t) GetMessageTime (); + + event = gdk_scroll_event_new (self->surface, + self->device, + NULL, time, state, + self->pan_x - pan_x, + self->pan_y - pan_y, + FALSE, + GDK_SCROLL_UNIT_SURFACE); + _gdk_win32_append_event (event); + + self->pan_x = pan_x; + self->pan_y = pan_y; + } + break; + case GESTURE_ZOOM: + { + GdkModifierType state; + uint32_t time; + POINT cursor = {0, 0}; + float scale; + GdkEvent *event; + + scale = transform[0]; + + state = util_get_modifier_state (); + time = (uint32_t) GetMessageTime (); + _gdk_win32_get_cursor_pos (&cursor); + + ScreenToClient (GDK_SURFACE_HWND (self->surface), &cursor); + + if (!self->sequence) + self->sequence = util_get_next_sequence (); + + event = gdk_touchpad_event_new_pinch (self->surface, self->sequence, self->device, + time, state, self->phase, cursor.x, cursor.y, + 2, 0.0, 0.0, scale, 0.0); + _gdk_win32_append_event (event); + + self->scale = scale; + self->phase = GDK_TOUCHPAD_GESTURE_PHASE_UPDATE; + } + break; + default: + g_assert_not_reached (); + break; + } + + return S_OK; +} + +static STDMETHODIMP +DManipEventHandler_OnViewportStatusChanged (IDirectManipulationViewportEventHandler *self_, + IDirectManipulationViewport *viewport, + DIRECTMANIPULATION_STATUS current, + DIRECTMANIPULATION_STATUS previous) +{ + DManipEventHandler *self = (DManipEventHandler*) self_; + + if (previous == DIRECTMANIPULATION_RUNNING) + { + switch (self->gesture) + { + case GESTURE_PAN: + { + GdkModifierType state; + uint32_t time; + GdkEvent *event; + + state = util_get_modifier_state (); + time = (uint32_t) GetMessageTime (); + + event = gdk_scroll_event_new (self->surface, self->device, + NULL, time, state, + 0.0, 0.0, TRUE, + GDK_SCROLL_UNIT_SURFACE); + _gdk_win32_append_event (event); + } + break; + case GESTURE_ZOOM: + { + GdkModifierType state; + uint32_t time; + POINT cursor = {0, 0}; + GdkEvent *event; + + if (self->phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN) + break; + + state = util_get_modifier_state (); + time = (uint32_t) GetMessageTime (); + _gdk_win32_get_cursor_pos (&cursor); + + ScreenToClient (GDK_SURFACE_HWND (self->surface), &cursor); + + event = gdk_touchpad_event_new_pinch (self->surface, self->sequence, self->device, + time, state, GDK_TOUCHPAD_GESTURE_PHASE_END, + cursor.x, cursor.y, 2, 0., 0., self->scale, + 0.); + _gdk_win32_append_event (event); + } + break; + default: + g_assert_not_reached (); + break; + } + + dmanip_event_handler_running_state_clear (self); + reset_viewport (viewport); + } + + return S_OK; +} + +static void +dmanip_event_handler_running_state_clear (DManipEventHandler *handler) +{ + handler->scale = 1.0; + handler->pan_x = 0.0; + handler->pan_y = 0.0; + + handler->phase = GDK_TOUCHPAD_GESTURE_PHASE_BEGIN; + handler->sequence = NULL; +} + +static DManipEventHandler* +dmanip_event_handler_new (GdkSurface *surface, + int gesture) +{ + static IDirectManipulationViewportEventHandlerVtbl vtable = { + DManipEventHandler_QueryInterface, + DManipEventHandler_AddRef, + DManipEventHandler_Release, + DManipEventHandler_OnViewportStatusChanged, + DManipEventHandler_OnViewportUpdated, + DManipEventHandler_OnContentUpdated, + }; + DManipEventHandler *handler; + + handler = g_new0 (DManipEventHandler, 1); + handler->vtable = &vtable; + handler->reference_count = 1; + + handler->gesture = gesture; + + handler->surface = surface; + handler->device = _gdk_device_manager->core_pointer; + + dmanip_event_handler_running_state_clear (handler); + + return handler; +} + +static void +dmanip_event_handler_free (DManipEventHandler *handler) +{ + g_free (handler); +} + + +/* }}} */ +/* {{{ Viewport utils */ + + +static void +reset_viewport (IDirectManipulationViewport *viewport) +{ + IDirectManipulationContent *content = NULL; + REFIID iid = &IID_IDirectManipulationContent; + float identity[6] = {1., 0., 0., 1., 0., 0.}; + HRESULT hr; + + hr = IDirectManipulationViewport_GetPrimaryContent (viewport, iid, (void**)&content); + HR_CHECK (hr); + + hr = IDirectManipulationContent_SyncContentTransform (content, identity, + G_N_ELEMENTS (identity)); + HR_CHECK (hr); +} + +static void +close_viewport (IDirectManipulationViewport **p_viewport) +{ + IDirectManipulationViewport *viewport = *p_viewport; + + if (viewport) + { + IDirectManipulationViewport_Abandon (viewport); + IUnknown_Release (viewport); + + *p_viewport = NULL; + } +} + +static void +create_viewport (GdkSurface *surface, + int gesture, + IDirectManipulationViewport **pViewport) +{ + DIRECTMANIPULATION_CONFIGURATION configuration = 0; + HWND hwnd = GDK_SURFACE_HWND (surface); + IDirectManipulationViewportEventHandler *handler; + DWORD cookie = 0; + HRESULT hr; + + hr = IDirectManipulationManager_CreateViewport (dmanipulation_manager, NULL, hwnd, + &IID_IDirectManipulationViewport, + (void**) pViewport); + HR_CHECK_GOTO (hr, failed); + + switch (gesture) + { + case GESTURE_PAN: + configuration = DIRECTMANIPULATION_CONFIGURATION_INTERACTION | + DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_X | + DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_Y; + break; + case GESTURE_ZOOM: + configuration = DIRECTMANIPULATION_CONFIGURATION_INTERACTION | + DIRECTMANIPULATION_CONFIGURATION_SCALING; + break; + default: + g_assert_not_reached (); + break; + } + + handler = (IDirectManipulationViewportEventHandler*) + dmanip_event_handler_new (surface, gesture); + + hr = IDirectManipulationViewport_AddEventHandler (*pViewport, hwnd, handler, &cookie); + HR_CHECK_GOTO (hr, failed); + + hr = IDirectManipulationViewport_ActivateConfiguration (*pViewport, configuration); + HR_CHECK_GOTO (hr, failed); + + hr = IDirectManipulationViewport_SetViewportOptions (*pViewport, + DIRECTMANIPULATION_VIEWPORT_OPTIONS_DISABLEPIXELSNAPPING); + + hr = IDirectManipulationViewport_Enable (*pViewport); + HR_CHECK_GOTO (hr, failed); + + // drop our initial reference + IUnknown_Release (handler); + return; + +failed: + if (handler) + IUnknown_Release (handler); + + close_viewport (pViewport); +} + + +/* }}} */ +/* {{{ Public */ + + +void gdk_dmanipulation_initialize (void) +{ + if (!getPointerType) + { + HMODULE user32_mod; + + user32_mod = LoadLibraryW (L"user32.dll"); + if (!user32_mod) + { + WIN32_API_FAILED ("LoadLibraryW"); + return; + } + + getPointerType = (getPointerType_t) + GetProcAddress (user32_mod, "GetPointerType"); + + if (!getPointerType) + return; + } + + if (!gdk_win32_ensure_com ()) + return; + + if (dmanipulation_manager == NULL) + { + HRESULT hr; + + hr = CoCreateInstance (&CLSID_DirectManipulationManager, + NULL, + CLSCTX_INPROC_SERVER, + &IID_IDirectManipulationManager, + (LPVOID*)&dmanipulation_manager); + if (FAILED (hr)) + { + if (hr == REGDB_E_CLASSNOTREG || hr == E_NOINTERFACE); + /* Not an error, + * DirectManipulation is not available */ + else HR_LOG (hr); + } + } +} + +void gdk_dmanipulation_initialize_surface (GdkSurface *surface) +{ + GdkWin32Surface *surface_win32; + HRESULT hr; + + if (!dmanipulation_manager) + return; + + surface_win32 = GDK_WIN32_SURFACE (surface); + + create_viewport (surface, GESTURE_PAN, + &surface_win32->dmanipulation_viewport_pan); + + create_viewport (surface, GESTURE_ZOOM, + &surface_win32->dmanipulation_viewport_zoom); + + hr = IDirectManipulationManager_Activate (dmanipulation_manager, + GDK_SURFACE_HWND (surface)); + HR_CHECK (hr); +} + +void gdk_dmanipulation_finalize_surface (GdkSurface *surface) +{ + GdkWin32Surface *surface_win32 = GDK_WIN32_SURFACE (surface); + + close_viewport (&surface_win32->dmanipulation_viewport_zoom); + close_viewport (&surface_win32->dmanipulation_viewport_pan); +} + +void gdk_dmanipulation_maybe_add_contact (GdkSurface *surface, + MSG *msg) +{ + POINTER_INPUT_TYPE type = PT_POINTER; + UINT32 pointer_id = GET_POINTERID_WPARAM (msg->wParam); + + if (!dmanipulation_manager) + return; + + if (!getPointerType) + return; + + if G_UNLIKELY (!getPointerType (pointer_id, &type)) + { + WIN32_API_FAILED_LOG_ONCE ("GetPointerType"); + return; + } + + if (type == PT_TOUCHPAD) + { + GdkWin32Surface *surface_win32 = GDK_WIN32_SURFACE (surface); + HRESULT hr; + + hr = IDirectManipulationViewport_SetContact (surface_win32->dmanipulation_viewport_pan, + pointer_id); + HR_CHECK (hr); + + hr = IDirectManipulationViewport_SetContact (surface_win32->dmanipulation_viewport_zoom, + pointer_id); + HR_CHECK (hr); + } +} + + +/* }}} */ +/* {{{ Utils */ + + +static gpointer +util_get_next_sequence (void) +{ + //TODO: sequence of other input types? + static unsigned char *sequence_counter = 0; + + if (++sequence_counter == 0) + sequence_counter++; + + return sequence_counter; +} + +static GdkModifierType +util_get_modifier_state (void) +{ + GdkModifierType mask = 0; + BYTE kbd[256]; + + GetKeyboardState (kbd); + if (kbd[VK_SHIFT] & 0x80) + mask |= GDK_SHIFT_MASK; + if (kbd[VK_CAPITAL] & 0x80) + mask |= GDK_LOCK_MASK; + if (kbd[VK_CONTROL] & 0x80) + mask |= GDK_CONTROL_MASK; + if (kbd[VK_MENU] & 0x80) + mask |= GDK_ALT_MASK; + + return mask; +} + +static gboolean +util_handler_free (gpointer handler) +{ + dmanip_event_handler_free ((DManipEventHandler*)handler); + + return G_SOURCE_REMOVE; +} + + +/* }}} */ diff --git a/gdk/win32/gdkinput-dmanipulation.h b/gdk/win32/gdkinput-dmanipulation.h new file mode 100644 index 0000000000..77d603c0cf --- /dev/null +++ b/gdk/win32/gdkinput-dmanipulation.h @@ -0,0 +1,32 @@ +/* gdkinput-dmanipulation.h + * + * Copyright © 2022 the GTK team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __GDK_INPUT_DMANIPULATION_H__ +#define __GDK_INPUT_DMANIPULATION_H__ + +void gdk_dmanipulation_initialize (void); + +void gdk_dmanipulation_initialize_surface (GdkSurface *surface); +void gdk_dmanipulation_finalize_surface (GdkSurface *surface); + +void gdk_dmanipulation_maybe_add_contact (GdkSurface *surface, + MSG *msg); + +#endif /* __GDK_INPUT_DMANIPULATION_H__ */ diff --git a/gdk/win32/gdkmain-win32.c b/gdk/win32/gdkmain-win32.c index d140d8e644..d6f8dc82ed 100644 --- a/gdk/win32/gdkmain-win32.c +++ b/gdk/win32/gdkmain-win32.c @@ -36,6 +36,7 @@ #include "gdkkeysyms.h" #include "gdkintl.h" #include "gdkprivate-win32.h" +#include "gdkinput-dmanipulation.h" #include "gdkwin32.h" #include @@ -49,6 +50,12 @@ static gboolean gdk_synchronize = FALSE; +/* Whether GDK initialized COM */ +static gboolean co_initialized = FALSE; + +/* Whether GDK initialized OLE */ +static gboolean ole_initialized = FALSE; + void _gdk_win32_surfaceing_init (void) { @@ -67,6 +74,82 @@ _gdk_win32_surfaceing_init (void) GDK_NOTE (EVENTS, g_print ("input_locale: %p\n", _gdk_input_locale)); _gdk_win32_clipdrop_init (); + + gdk_dmanipulation_initialize (); +} + +gboolean +gdk_win32_ensure_com (void) +{ + if (!co_initialized) + { + /* UI thread should only use STA model. See + * -> https://devblogs.microsoft.com/oldnewthing/20080424-00/?p=22603 + * -> https://devblogs.microsoft.com/oldnewthing/20071018-00/?p=24743 + */ + const DWORD flags = COINIT_APARTMENTTHREADED | + COINIT_DISABLE_OLE1DDE; + HRESULT hr; + + hr = CoInitializeEx (NULL, flags); + if (SUCCEEDED (hr)) + co_initialized = TRUE; + else switch (hr) + { + case RPC_E_CHANGED_MODE: + g_warning ("COM runtime already initialized on the main " + "thread with an incompatible apartment model"); + break; + default: + HR_LOG (hr); + break; + } + } + + return co_initialized; +} + +static void +gdk_win32_finalize_com (void) +{ + if (co_initialized) + { + CoUninitialize (); + co_initialized = FALSE; + } +} + +gboolean +gdk_win32_ensure_ole (void) +{ + if (!ole_initialized) + { + HRESULT hr = OleInitialize (NULL); + if (SUCCEEDED (hr)) + ole_initialized = TRUE; + else switch (hr) + { + case RPC_E_CHANGED_MODE: + g_warning ("Failed to initialize the OLE2 runtime because " + "the thread has an incompatible apartment model"); + break; + default: + HR_LOG (hr); + break; + } + } + + return ole_initialized; +} + +static void +gdk_win32_finalize_ole (void) +{ + if (ole_initialized) + { + OleUninitialize (); + ole_initialized = FALSE; + } } void diff --git a/gdk/win32/gdkprivate-win32.h b/gdk/win32/gdkprivate-win32.h index 652272c5cc..3ba99dce83 100644 --- a/gdk/win32/gdkprivate-win32.h +++ b/gdk/win32/gdkprivate-win32.h @@ -196,6 +196,9 @@ void _gdk_remove_modal_window (GdkSurface *window); GdkSurface *_gdk_modal_current (void); gboolean _gdk_modal_blocked (GdkSurface *window); +gboolean gdk_win32_ensure_com (void); +gboolean gdk_win32_ensure_ole (void); + #ifdef G_ENABLE_DEBUG void _gdk_win32_print_paletteentries (const PALETTEENTRY *pep, const int nentries); @@ -252,6 +255,13 @@ void _gdk_other_api_failed (const char *where, #define GDI_CALL(api, arglist) (api arglist ? 1 : (WIN32_GDI_FAILED (#api), 0)) #define API_CALL(api, arglist) (api arglist ? 1 : (WIN32_API_FAILED (#api), 0)) +#define HR_LOG(hr) + +#define HR_CHECK_RETURN(hr) { if G_UNLIKELY (FAILED (hr)) return; } +#define HR_CHECK_RETURN_VAL(hr, val) { if G_UNLIKELY (FAILED (hr)) return val; } +#define HR_CHECK(hr) +#define HR_CHECK_GOTO(hr, label) { if G_UNLIKELY (FAILED (hr)) goto label; } + extern LRESULT CALLBACK _gdk_win32_surface_procedure (HWND, UINT, WPARAM, LPARAM); extern GdkDisplay *_gdk_display; diff --git a/gdk/win32/gdksurface-win32.c b/gdk/win32/gdksurface-win32.c index 938737e86b..cef3d4c8f5 100644 --- a/gdk/win32/gdksurface-win32.c +++ b/gdk/win32/gdksurface-win32.c @@ -44,6 +44,7 @@ #include "gdktoplevelprivate.h" #include "gdkwin32surface.h" #include "gdkwin32cursor.h" +#include "gdkinput-dmanipulation.h" #include "gdkinput-winpointer.h" #include "gdkglcontext-win32.h" #include "gdkdisplay-win32.h" @@ -639,8 +640,14 @@ _gdk_win32_display_create_surface (GdkDisplay *display, } gdk_surface_set_egl_native_window (surface, (void *) impl->handle); - if (display_win32->tablet_input_api == GDK_WIN32_TABLET_INPUT_API_WINPOINTER) - gdk_winpointer_initialize_surface (surface); + + if (surface_type != GDK_SURFACE_TEMP) + { + if (display_win32->tablet_input_api == GDK_WIN32_TABLET_INPUT_API_WINPOINTER) + gdk_winpointer_initialize_surface (surface); + + gdk_dmanipulation_initialize_surface (surface); + } _gdk_win32_surface_enable_transparency (surface); _gdk_win32_surface_register_dnd (surface); diff --git a/gdk/win32/gdksurface-win32.h b/gdk/win32/gdksurface-win32.h index 08bd0a20b7..cff41117ef 100644 --- a/gdk/win32/gdksurface-win32.h +++ b/gdk/win32/gdksurface-win32.h @@ -32,6 +32,7 @@ #include "gdk/gdkcursor.h" #include +#include #ifdef HAVE_EGL # include @@ -339,6 +340,9 @@ struct _GdkWin32Surface } next_layout; gboolean force_recompute_size; + IDirectManipulationViewport *dmanipulation_viewport_pan; + IDirectManipulationViewport *dmanipulation_viewport_zoom; + #ifdef HAVE_EGL guint egl_force_redraw_all : 1; #endif diff --git a/gdk/win32/meson.build b/gdk/win32/meson.build index d368648624..156c9ab730 100644 --- a/gdk/win32/meson.build +++ b/gdk/win32/meson.build @@ -17,6 +17,7 @@ gdk_win32_sources = files([ 'gdkglcontext-win32-wgl.c', 'gdkglobals-win32.c', 'gdkhdataoutputstream-win32.c', + 'gdkinput-dmanipulation.c', 'gdkinput-winpointer.c', 'gdkkeys-win32.c', 'gdkkeys-win32-impl.c', -- 2.30.2